package com.work.flow.service.impl;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.work.flow.common.NodeCalculationModel;
import com.work.flow.common.ThreadPoolUtil;
import com.work.flow.common.UUIDTool;
import com.work.flow.dao.StoryBoardDao;
import com.work.flow.feign.ShpFeignService;
import com.work.flow.model.*;
import com.work.flow.scoket.WebSocketServer;
import com.work.flow.service.FileService;
import com.work.flow.service.StoryBoardService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class StoryBoardServiceImpl implements StoryBoardService {
    public static final String DATASOURCE_PATH_KEY = "path";


    @Autowired
    StoryBoardDao storyBoardDao;
    @Autowired
    FileService fileService;
    @Autowired
    ShpFeignService shpFeignService;

    @Override
    public String merge(StoryBoard storyBoard) {
        if (StringUtils.isBlank(storyBoard.getUuid())) {
            storyBoard.setUuid(UUIDTool.get32UUID());
            storyBoardDao.insertSelective(storyBoard);
        } else {
            storyBoardDao.updateByPrimaryKeySelective(storyBoard);
        }
        return storyBoard.getUuid();
    }

    @Override
    public void delete(String uuid) {
        storyBoardDao.deleteByPrimaryKey(uuid);
    }

    @Override
    public StoryBoard getById(String uuid) {
        return storyBoardDao.selectByPrimaryKey(uuid);
    }

    /**
     * 开始模型计算任务
     *
     * @param id
     */
    @Override
    public void startTask(String id) {
        ThreadPoolUtil.execute(new Runnable() {
            @Override
            public void run() {
                WebSocketServer.sendInfo("开始执行任务", id);
                //整个模型参数
                StoryBoard storyBoard = getById(id);
                Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
                gson.serializeNulls();
                List<Node> nodes = gson.fromJson(storyBoard.getNodeList(), new TypeToken<List<Node>>() {
                }.getType());
                List<Link> links = gson.fromJson(storyBoard.getLinkList(), new TypeToken<List<Link>>() {
                }.getType());
                System.out.println("节点数量" + nodes.size());
                System.out.println("连线数量" + nodes.size());
                WebSocketResult webSocketResult=WebSocketResult.MakeResult();
                webSocketResult.setStoryId(id);
                webSocketResult.setFirst(true);

                try {
                    nodes= NodeCalculationModel.getNodesByOrder(nodes,links);

                    if(nodes==null){
                        throw new Exception("无节点数据");
                    }else if(nodes.size()==1){
                        webSocketResult.setLast(true);
                    }


                    String path="";

                    for (int i = 0; i < nodes.size(); i++) {
                        Node node=nodes.get(i);
                        webSocketResult.setName(node.getMeta().getName());
                        updateDateSource(node);
                        if(i==1){
                            webSocketResult.setFirst(false);
                        }
                        //最后一个节点处理
                        if(i==nodes.size()-1){
                            webSocketResult.setLast(true);
                        }
                        webSocketResult.setNodeId(node.getId());

                        path=executeModel(node,path);
                        //成功后发出广播
                        webSocketResult.updateTime();

                        webSocketResult.setMsg(path);
                        webSocketResult.setSuccess(true);
                        WebSocketServer.sendInfo(webSocketResult.toString(), webSocketResult.getStoryId());
                    }



                } catch (Exception e) {
                    e.printStackTrace();
                    //失败后广播
                    webSocketResult.setSuccess(false);
                    webSocketResult.setMsg(e.getMessage());
                    webSocketResult.updateTime();
                    WebSocketServer.sendInfo(webSocketResult.toString(), webSocketResult.getStoryId());
                }

            }
        });


    }

    /**
     * 更新所有的source类型数据，将其替换为
     * @param node
     */
    private void updateDateSource(Node node){
        List<NodeParam> paramList=node.getMeta().getPanel();
        for (int i = 0; i < paramList.size(); i++) {
            NodeParam nodeParam= paramList.get(i);
            if("source".equals(nodeParam.getType())&&StringUtils.isNotBlank(nodeParam.getValue())&&nodeParam.getValue().length()==32){
                nodeParam.setValue(fileService.getFileById(nodeParam.getValue()).getPath());
            }
        }
    }

    /**
     * 执行模型
     *
     * @param node
     * @return
     */
    @Override
    public String executeModel(Node node) throws Exception {
        BaseResult baseResult= shpFeignService.analysis(nodeToMap(node.getMeta().getPanel()), node.getMeta().getType());
        if(baseResult.getCode()==200){
            return baseResult.getResult();
        }else {

            throw new Exception("执行节点失败:"+baseResult.getResult());
        }

    }

    /**
     * 参数提取
     * @param nodeParams
     * @return
     */
    private Map<String, String> nodeToMap(List<NodeParam> nodeParams) {
        Map<String, String> map = new HashMap<>(nodeParams.size());
        for (int i = 0; i < nodeParams.size(); i++) {
            NodeParam nodeParam = nodeParams.get(i);
            map.put(nodeParam.getKey(), nodeParam.getValue());
        }
        return map;

    }


    /**
     * 执行模型
     *
     * @param node
     * @param dataSource
     * @return
     */
    @Override
    public String executeModel(Node node, String dataSource) throws Exception {
        String path = node.getKey(DATASOURCE_PATH_KEY);
        if("inherit".equals(path)||StringUtils.isBlank(path)){
            NodeParam nodeParam = new NodeParam();
            nodeParam.setKey(DATASOURCE_PATH_KEY);
            nodeParam.setValue(dataSource);
            node.getMeta().getPanel().add(nodeParam);
        }
        return executeModel(node);
    }

    /**
     * 删除模型
     *
     * @param id
     */
    @Override
    public void deleteById(String id) {
        storyBoardDao.deleteByPrimaryKey(id);
    }

    @Override
    public long getCount(String key) {
        return storyBoardDao.getCount(key);
    }

    @Override
    public List<StoryBoard> queryByPage(PageModel pageModel) {
        return storyBoardDao.queryByPage(pageModel);
    }
}
